//----------------------------------------------------------------------------------------------------------------------
// Copyright (c) 2012 James Whitworth
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the \"Software\"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//----------------------------------------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------------
// Used to describes a function argument, function return type or member variable.
//----------------------------------------------------------------------------------------------------------------------
class Parameter extends CodeGenerator
{
  type = null
  owner = null
  value = null

  constructor(_type = "void", _name = "", _flags = 0)
  {
    assert(typeof(_type) == "string")
    assert(typeof(_name) == "string")
    assert(typeof(_flags) == "integer")

    type = _type
    name = _name
    flags = _flags
  }


  // Write the parameter as part of a function declaration.
  //
  function write_declaration(stream)
  {
    if (owner != null && has_flags(CodeGenerator.kStatic))
    {
      stream.write("static ")
    }

    local require_space = write_type(stream)

    if (typeof(type) == "string" && name.len() > 0)
    {
      if (require_space)
      {
        stream.write(" ")
      }
      stream.write(name)
    }
  }

  // Write the parameter as part of a function definition.
  //
  function write_definition(stream, file_type)
  {
    local require_space = write_type(stream)

    if (typeof(type) == "string" && name.len() > 0 && !has_flags(CodeGenerator.kUnused))
    {
      if (require_space)
      {
        stream.write(" ")
      }
      
      if (owner != null)
      {
        assert(typeof(owner) == "instance")
        assert(owner.name.len() > 0)
        assert(typeof(owner.name) == "string")

        stream.write("%s::", owner.name)
      }
      stream.write(name)
 
      if (typeof(value) == "string" && value.len() > 0)
      {
        stream.write(" = %s", value)
      }
    }
  }

  // Write the required template parameter declaration for this parameter if one is needed
  //
  function write_template(stream)
  {
    if (is_templated())
    {
      assert(typeof(type) == "string")
      assert(type.len() > 0)
      stream.write("typename %s", type)
    }
  }

  // Write only the type information for the parameter. Used by write_declaration and write_definition,
  // also useful when writing function return types.
  //
  function write_type(stream)
  {
    if (has_flags(CodeGenerator.kConst))
    {
      stream.write("const ")
    }

    stream.write("%s", type)

    if (has_flags(CodeGenerator.kPointer))
    {
      stream.write(" *")
      return false
    }
    else if (has_flags(CodeGenerator.kReference))
    {
      stream.write(" &")
      return false
    }

    return true
  }
}

//----------------------------------------------------------------------------------------------------------------------
class NullParameter extends Parameter
{
  constructor()
  {
    base.constructor("", "", 0)
  }

  function write_declaration(stream)
  {
    // nothing to do
  }

  function write_definition(stream, file_type)
  {
    // nothing to do
  }

  function write_template(stream)
  {
    // nothing to do
  }

  function write_type(stream)
  {
    // nothing to do
    return false
  }
}